package com.seres.config;

import cn.hutool.core.collection.ListUtil;
import com.alibaba.fastjson.JSON;
import com.seres.annotation.AuthToken;
import com.seres.annotation.ConfigEvent;
import com.seres.cache.BaseCache;
import com.seres.enums.ConfigEventEnum;
import com.seres.redis.RedisCache;
import com.seres.util.AnnotationUtil;
import com.seres.util.StreamTools;
import com.seres.util.StringUtils;
import com.seres.vo.SysInterface;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Tan-Bowen
 * @version 1.0
 * @description TODO 扫描所有接口
 * @date 2021/8/2 10:59
 */
@Slf4j
@Component
@ConfigEvent(ConfigEventEnum.INTERFACE_CACHE)
public class CacheInterface extends BaseCache {

//    private static final Map<String, SysInterface> urls = new HashMap<>();

    @Resource
    private ApplicationContext applicationContext;

    @Value("${spring.application.name}")
    private String applicationName;

    @Autowired
    private RedisCache redisCache;


    @Override
    public void init() {
        String key = applicationName;
        List<SysInterface> list = scanUrls();
        redisCache.del(key);
        if (!list.isEmpty()) {
            redisCache.cacheOneWeek(JSON.toJSONString(list), key);
        }
        log.info("加载所有接口完成:{}", list.size());
    }

    public List<SysInterface> urls() {
        String key = applicationName;
        return redisCache.getList(key, SysInterface.class);
    }

    public List<SysInterface> getUrlsByServers(List<String> names) {
        List<SysInterface> res = new ArrayList<>();
        names.forEach(e -> {
            List<SysInterface> list = redisCache.getList(e, SysInterface.class);
            if (!list.isEmpty()) {
                res.addAll(list);
            }
        });
        return res;
    }

    public Map<String, SysInterface> urlMap() {
        return StreamTools.toMap(urls(), SysInterface::getMethodPath);
    }

    public SysInterface get(String url) {
        return urlMap().get(url);
    }

    public List<SysInterface> all() {
        return urls();
    }

    public Map<String, SysInterface> getUrlMap() {
        return StreamTools.toMap(all(), SysInterface::getMethodPath);
    }

    public SysInterface getInterface(String url) {
        return getUrlMap().get(url);
    }

    public List<SysInterface> scanUrls() {
        Map<String, Object> controllers = applicationContext.getBeansWithAnnotation(RestController.class);
//        List<String> urls = new ArrayList<>();
        List<SysInterface> res = new ArrayList<>();
        for (Map.Entry<String, Object> entry : controllers.entrySet()) {
            Object value = entry.getValue();
            Class<?> aClass = AopUtils.getTargetClass(value);
            String url = "";
            if (aClass.isAnnotationPresent(RequestMapping.class)) {
                RequestMapping annotation = aClass.getAnnotation(RequestMapping.class);
                String[] path = annotation.value();
                url = annotationValue(path);
            }

            Method[] declaredMethods = aClass.getDeclaredMethods();
            String className = aClass.getName();
            String classRemark = AnnotationUtil.getApiMode(aClass);
            if (declaredMethods.length == 0) {
                continue;
            }
            for (Method method : declaredMethods) {
                String v = this.getUrl(method);
                if (v == null) {
                    continue;
                }
                String[] val = v.split(",");
                AuthToken authToken = method.getAnnotation(AuthToken.class);
                SysInterface sysInterface = SysInterface.builder()
                        .className(className)
                        .classRemark(classRemark)
                        .name(method.getName())
                        .path(val[0])
                        .classPath(url)
                        .methodPath("/"+applicationName+StringUtils.append(url, val[0]))
                        .remarks(AnnotationUtil.getApiPro(method))
                        .auth(authToken.checkPower())
                        .token(authToken.checkToken())
                        .methodType(val[1])
                        .build();
                res.add(sysInterface);

            }
        }
        return res;
    }

    public String getUrl(Method method) {
        if (!AnnotationUtil.checkAnn(method, AuthToken.class)) return null;
        if (AnnotationUtil.checkAnn(method, RequestMapping.class)) {
            RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
            return annotationValue(requestMapping.value()) + "," + requestMapping.method()[0].name();
        }
        if (AnnotationUtil.checkAnn(method, PostMapping.class)) {
            return annotationValue(method.getAnnotation(PostMapping.class).value()) + ",post";
        }
        if (AnnotationUtil.checkAnn(method, GetMapping.class)) {
            return annotationValue(method.getAnnotation(GetMapping.class).value()) + ",get";
        }
        if (AnnotationUtil.checkAnn(method, DeleteMapping.class)) {
            return annotationValue(method.getAnnotation(DeleteMapping.class).value()) + ",delete";
        }
        if (AnnotationUtil.checkAnn(method, PutMapping.class)) {
            return annotationValue(method.getAnnotation(PutMapping.class).value()) + ",put";
        }
        return null;
    }


    public String annotationValue(Object[] args) {
        String res = "";
        for (Object arg : args) {
            res = StringUtils.append(res, arg.toString());
        }
        return res;
    }


}

